package com.tobeface.sns.interfaces.admin;

import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.kissme.core.web.Webs;
import com.kissme.lang.Preconditions;
import com.tobeface.sns.application.security.UserService;
import com.tobeface.sns.domain.User;
import com.tobeface.sns.domain.security.Member;
import com.tobeface.sns.interfaces.constants.SubjectAttrConstants;
import com.tobeface.sns.interfaces.exception.InvalidCaptchaException;
import com.tobeface.sns.interfaces.support.SubjectAwareController;
import com.tobeface.sns.interfaces.util.HttpCaptchaHelper;
import com.tobeface.sns.interfaces.util.JsonMessage;

/**
 * 
 * @author loudyn
 * 
 */
@Controller
public class LoginController extends SubjectAwareController {

	public static final int UNKNOWN_ACCOUT_ERROR_CODE = 1;
	public static final int LOCKED_ACCOUT_ERROR_CODE = 2;
	public static final int AUTHENTICATION_ERROR_CODE = 4;
	public static final int INVALID_CAPTCHA_ERROR_CODE = 8;
	public static final int INVALID_SESSION_ERROR_CODE = 16;
	public static final int UNKNOWN_ERROR_CODE = 32;

	private UserService userService;

	@Autowired
	public LoginController(UserService userService) {
		Preconditions.notNull(userService);

		this.userService = userService;
	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping(value = { "/", "/login", "/signin" }, method = GET)
	public String login() {
		return "admin/login";
	}

	/**
	 * 
	 * @param action
	 * @param request
	 * @param session
	 * @return
	 */
	@RequestMapping(value = { "/", "/login", "/signin" }, method = POST)
	@ResponseBody
	public JsonMessage login(@RequestHeader(value = "X-Requested-With", required = false) String requestedWith, HttpServletRequest request, HttpSession session) {

		if (!Webs.isAjax(requestedWith)) {
			return JsonMessage.one().notOk();
		}

		Subject subject = getSubject();

		try {

			checkCaptcha(request, session);
			tryLogin(request, subject);

			applyToSubject(subject);
			return JsonMessage.one().ok();
		} catch (Exception e) {
			int code = translateLoginExceptionCode(e);
			return JsonMessage.one().notOk().code(code);
		}
	}

	@RequestMapping(value = "/proved-username/{username}", method = POST)
	@ResponseBody
	public JsonMessage whetherExistByUsername(@RequestHeader(value = "X-Requested-With", required = false) String requestedWith,
			@PathVariable("username") String username) {

		if (!Webs.isAjax(requestedWith)) {
			return null;
		}
		
		User user = userService.getByUsername(username);
		
		if (user == null) {
			return JsonMessage.one().notOk().code(UNKNOWN_ACCOUT_ERROR_CODE);
		}
		return JsonMessage.one().ok();
	}

	private void checkCaptcha(HttpServletRequest request, HttpSession session) {
		String captchaCode = WebUtils.getCleanParam(request, "captcha");
		HttpCaptchaHelper.mustValidate(session);
		HttpCaptchaHelper.checkCaptcha(captchaCode, session);
	}

	private void tryLogin(HttpServletRequest request, Subject subject) {

		AuthenticationToken token = createToken(request);
		subject.login(token);
	}

	private AuthenticationToken createToken(HttpServletRequest request) {
		String username = WebUtils.getCleanParam(request, "username");
		String password = WebUtils.getCleanParam(request, "password");

		Member member = new Member();
		member.setUsername(username);
		member.setPassword(password);
		member.encodePassword();

		String rememberMeAsString = WebUtils.getCleanParam(request, "rememberMe");
		boolean rememberMe = false;
		if (null != rememberMeAsString) {
			rememberMe = Boolean.valueOf(rememberMeAsString);
		}
		String host = request.getRemoteHost();
		return new UsernamePasswordToken(member.getUsername(), member.getPassword(), rememberMe, host);
	}

	private void applyToSubject(Subject subject) {

		String username = subject.getPrincipal().toString();
		User user = userService.getByUsername(username);

		subject.getSession().setAttribute(SubjectAttrConstants.USER_AWARE_CONSTANT, user);
	}

	private int translateLoginExceptionCode(Exception e) {

		if (e instanceof InvalidCaptchaException) {
			return INVALID_CAPTCHA_ERROR_CODE;
		}

		if (e instanceof UnknownAccountException) {
			return UNKNOWN_ACCOUT_ERROR_CODE;
		}

		if (e instanceof LockedAccountException) {
			return LOCKED_ACCOUT_ERROR_CODE;
		}

		if (e instanceof AuthenticationException) {
			return AUTHENTICATION_ERROR_CODE;
		}

		return UNKNOWN_ERROR_CODE;
	}
}
